import { i18n } from 'boot/i18n'
import { createWarnTips, formatNumber, isEmpty, isJSON } from 'src/utils/utils'
import { fillDrawPoint } from 'src/views/MapCore/MapGlobal/utils/KonvaEvent.js'
import { dash, fontSize, replacePoint } from 'src/views/MapCore/MapGlobal/utils/MouseEvent'
import { packagePoints } from 'src/views/MapCore/MapGlobal/utils/PackagePoints'

const areaFields = {
  areaCode: 'areaCode', height: 'areaHeight', text: 'areaName', width: 'areaWidth', x: 'areaX', y: 'areaY'
}
const lineFields = {
  isBezier: 'isBezier', endPointCode: 'endPointCode', pathCode: 'lineCode', points: 'allPoints',
  startPointCode: 'startPointCode'
}
const pointFields = {
  pointCode: 'positionCode', pointName: 'positionName', pointType: 'positionType', x: 'positionX',
  y: 'positionY'
}
const textFields = { text: 'fontName', type: 'type', x: 'fontX', y: 'fontY' }

const formatSavePoint = point => {
  if (!point) return {}
  const deepAttrs = {}
  for (const key in pointFields) {
    if (!isEmpty(point[key])) deepAttrs[key] = point[key]
  }
  return deepAttrs
}
const formatSaveLine = line => {
  if (!line) return {}
  const deepAttrs = { bezier: line.bezier }
  for (const key in lineFields) {
    if (!isEmpty(line[key])) deepAttrs[key] = line[key]
  }
  return deepAttrs
}
const formatSaveArea = ({ border, fill, stroke, ...area }) => {
  if (!area) return {}
  const deepAttrs = {}, css = { border, fill, stroke }
  for (const key in areaFields) {
    if (!isEmpty(area[key])) deepAttrs[key] = area[key]
  }
  deepAttrs.css = JSON.stringify(css)
  return deepAttrs
}
const formatSaveText = ({ textColor, textFontSize, ...text }) => {
  if (!text) return {}
  const deepAttrs = {}, css = { textColor, textFontSize }
  for (const key in textFields) {
    if (!isEmpty(text[key])) deepAttrs[key] = text[key]
  }
  deepAttrs.css = JSON.stringify(css)
  return deepAttrs
}
const formatMapChild = (children = [], type) => {
  if (type === 'arrows') return []
  const mapChilds = []
  for (const item of children) {
    const deepItem = {}
    if (type === 'Layer') {
      deepItem.attrs = { name: item.attrs?.name }
      deepItem.children = formatMapChild(item.children, item.attrs?.name)
    } else if (type === 'lines') deepItem.attrs = formatSaveLine(item.attrs)
    else if (type === 'points') deepItem.attrs = formatSavePoint(item.attrs)
    else if (type === 'areas') deepItem.attrs = formatSaveArea(item.attrs)
    else if (type === 'texts') deepItem.attrs = formatSaveText(item.attrs)
    mapChilds.push(deepItem)
  }
  return mapChilds
}
export const formatMapJSON = mapJSON => {
  if (!mapJSON) return ''
  const { className = '', children = [] } = JSON.parse(mapJSON) || {}
  const shapeLayer = children.find(el => el.attrs?.name === 'shapeLayer') || {}
  return { className, children: formatMapChild(shapeLayer.children, 'Layer') }
}

const formatField = ['x', 'y', 'width', 'height']
export const formatImportArea = area => {
  if (!area) return {}
  const deepAttrs = {}, css = area.css && isJSON(area.css) ? JSON.parse(area.css) : {},
    css2 = area.css2 && isJSON(area.css2) ? JSON.parse(area.css2) : {}
  for (const key in areaFields) {
    if (formatField.includes(key)) deepAttrs[key] = Number(area[areaFields[key]]) || 0
    else if (!isEmpty(area[areaFields[key]])) deepAttrs[key] = area[areaFields[key]]
  }
  deepAttrs.textColor = css.textColor
  deepAttrs.textFontSize = css.textFontSize
  deepAttrs.fill = css2.fill
  deepAttrs.border = css2.border
  deepAttrs.dash = css2.border === 'dash' ? dash : []
  deepAttrs.stroke = css2.border === 'none' ? '' : css2.stroke
  return deepAttrs
}
export const formatImportText = text => {
  if (!text) return {}
  const deepAttrs = {}, css = text.css && isJSON(text.css) ? JSON.parse(text.css) : {}
  for (const key in textFields) {
    if (formatField.includes(key)) deepAttrs[key] = Number(text[textFields[key]]) || 0
    else if (!isEmpty(text[textFields[key]])) deepAttrs[key] = text[textFields[key]]
  }
  deepAttrs.textColor = css.textColor
  deepAttrs.textFontSize = css.textFontSize
  return deepAttrs
}
export const formatImportLine = line => {
  if (!line) return {}
  const deepAttrs = {}
  for (const key in lineFields) {
    if (!isEmpty(line[lineFields[key]])) deepAttrs[key] = line[lineFields[key]]
  }
  return deepAttrs
}
export const formatImportPoint = point => {
  if (!point) return {}
  const deepAttrs = {}
  for (const key in pointFields) {
    if (!isEmpty(point[pointFields[key]])) deepAttrs[key] = point[pointFields[key]]
  }
  return deepAttrs
}
export const getPointCode = async (x = 0, y = 0, mapGroundCode) => {
  return new Promise((resolve) => {
    x = formatNumber((x || 0) * 1000) + ''
    y = formatNumber((y || 0) * 1000) + ''
    resolve(`${x.padStart(6, '0')}${mapGroundCode || ''}${y.padStart(6, '0')}`)
  })
}

export const searchPointByCoord = (pointLayers = [], keyWords = '') => {
  if (!pointLayers.length || !keyWords) return
  let [x, y] = keyWords.split(','), targetPoint = null
  x = Number(x) || 0
  y = Number(y) || 0
  for (const pointLayer of pointLayers) {
    targetPoint = pointLayer.findOne(el => el.x() === x && el.y() === y)
    if (targetPoint) return targetPoint
  }
  createWarnTips({ title: i18n.t('MapCore.OperationTip6', [`${x}, ${y}`]) })
}
export const searchPointByCodeOrName = (pointLayers = [], keyWords = '') => {
  if (!pointLayers.length || !keyWords) return
  let targetPoint = null
  for (const pointLayer of pointLayers) {
    targetPoint = pointLayer.findOne(el => el.getAttr('pointName') === keyWords)
    if (targetPoint) return targetPoint
  }
  createWarnTips({ title: i18n.t('MapCore.OperationTip6', [keyWords]) })
}
export const searchLineByCode = (lineLayers = [], keyWords = '') => {
  if (!lineLayers.length || !keyWords) return
  let targetLine = null
  for (const lineLayer of lineLayers) {
    targetLine = lineLayer.findOne(
      el => el.getAttr('pathCode') === keyWords || `${el.getAttr('startPointCode')}-${el.getAttr('endPointCode')}` ===
        keyWords)
    if (targetLine) return targetLine
  }
  createWarnTips({ title: i18n.t('MapCore.OperationTip10', [keyWords]) })
}

const pointNonFields = ['pointCode', 'x', 'y']
const lineNonFields = ['endPointCode', 'pathCode', 'points', 'startPointCode']
export const updateLineAttrs = (operShape, form, isBatch) => {
  if (!operShape) return
  const attrs = operShape.getAttrs()
  for (const key in lineFields) {
    if (lineNonFields.includes(key) || (isBatch && isEmpty(form[key]))) continue
    if (form[key] !== attrs[key]) operShape.setAttr(key, form[key])
  }
}
export const batchUpdateLineAttrs = (lineGroup, batchSelected = [], form) => {
  if (!lineGroup) return
  const lineMap = new Map()
  lineGroup.find(line => lineMap.set(line.getAttr('uid'), line))
  batchSelected.forEach(shape => {
    const line = lineMap.get(shape.getAttr('uid'))
    line && updateLineAttrs(line, form, true)
  })
}
export const formatPositionType = (positionType = '') => {
  const { positionImageUrl } = packagePoints.value.find(p => positionType === p.positionPackageCode) || {}
  return positionImageUrl || ''
}
export const updatePointAttrs = async (operShape, batchSelected = [], form, isBatch) => {
  if (!operShape) return
  const attrs = operShape.getAttrs()
  for (const key in pointFields) {
    if (pointNonFields.includes(key) || (isBatch && isEmpty(form[key]))) continue
    if (form[key] !== attrs[key]) operShape.setAttr(key, form[key])
  }
  const replaceP = await fillDrawPoint(operShape.getAttr('pointType'))
  replaceP && replacePoint(operShape, replaceP)
  batchSelected.length && batchSelected.splice(0) && batchSelected.push(operShape)
}
export const batchUpdatePointAttrs = (canvas, batchSelected = [], form) => {
  if (!canvas) return
  batchSelected.forEach(async point => await updatePointAttrs(point, [], form, true))
}
export const updateAreaAttrs = (areaGroup, textGroup, operShape, form, onlyCoord) => {
  if (!operShape) return
  const { x = 0, y = 0, uid, textFontSize: textSize } = operShape.getAttrs()
  const findText = textGroup.find('Text').find(el => el.getAttr('uid') === uid)
  if (x !== form.x || y !== form.y) {
    const moveInfo = { x: form.x - x, y: form.y - y }
    operShape.move(moveInfo)
    if (findText) findText.move(moveInfo)
  }
  if (onlyCoord) return
  const { text, textFontSize, width = 0, border, fill, textColor, height } = form
  const dashArea = border === 'dash' ? dash : [], stroke = border === 'none' ? '' : form.stroke
  if (textFontSize !== textSize && findText) {
    findText.fontSize(formatNumber(textFontSize * fontSize))
    findText.offsetY(findText.height())
  }
  operShape.setAttrs({ dash: dashArea, fill, stroke, text, textFontSize, width, height: -height, border, textColor })
  if (findText) findText.setAttrs({ text, textFontSize, fill: textColor, textColor })
}
export const updateTextAttrs = (textGroup, operShape, form, onlyCoord) => {
  if (!operShape) return
  const { x = 0, y = 0, type } = operShape.getAttrs()
  if (form.x !== x || form.y !== y) {
    const findText = textGroup.find('Text')
      .find(el => el.x() === form.x && el.y() === form.y && el.getAttrs().type === type)
    if (findText) {
      createWarnTips({ title: i18n.t('MapCore.OperationTip8') })
      return
    }
    const moveInfo = { x: form.x - x, y: form.y - y }
    operShape.move(moveInfo)
  }
  if (onlyCoord) return
  const { text, textFontSize, textColor } = form
  operShape.fontSize(formatNumber(form.textFontSize * fontSize))
  operShape.setAttrs({ text, textFontSize, fill: textColor, textColor, offsetY: operShape.height() * 0.5 })
}

export const calculateSlamCoord = (slamInfo = {}, pointCoord = {}) => {
  const { x: coordX = 0, y: coordY = 0 } = pointCoord
  const { x = 0, y = 0, width = 0, height = 0, rotation = 0 } = slamInfo
  if (rotation === 90) return { x: formatNumber(coordX - x + height), y: formatNumber(coordY - y) }
  if (rotation === 180) return { x: formatNumber(coordX - x + width), y: formatNumber(coordY - y + height) }
  if (rotation === 270) return { x: formatNumber(coordX - x), y: formatNumber(coordY - y + width) }
  return { x: formatNumber(coordX - x), y: formatNumber(coordY - y) }
}

export const backwardCoordBySlam = (slamInfo = {}, pointCoord = {}) => {
  const { x: coordX = 0, y: coordY = 0 } = pointCoord
  const { x = 0, y = 0, width = 0, height = 0, rotation = 0 } = slamInfo
  if (rotation === 90) return { x: formatNumber(coordX + x - height), y: formatNumber(coordY + y) }
  if (rotation === 180) return { x: formatNumber(coordX + x - width), y: formatNumber(coordY + y - height) }
  if (rotation === 270) return { x: formatNumber(coordX + x), y: formatNumber(coordY + y - width) }
  return { x: formatNumber(coordX + x), y: formatNumber(coordY + y) }
}

export const calculateSceneCoord = (amrCoord = {}, datumMarkCoord = {}, datumMarkRotation = 0, n = 0) => {
  const amrX = amrCoord.x * Math.pow(10, n), amrY = amrCoord.y * Math.pow(10, n)
  const x = datumMarkCoord.x / 1000, y = datumMarkCoord.y / 1000
  // 角度转换为弧度
  const angleRad = (datumMarkRotation * Math.PI) / 180

  // 计算旋转矩阵元素
  const cosTheta = Math.cos(angleRad), sinTheta = Math.sin(angleRad)

  // 应用旋转和平移变换
  const originX = cosTheta * amrX - sinTheta * amrY + x, originY = sinTheta * amrX + cosTheta * amrY + y

  return { x: formatNumber(originX), y: formatNumber(originY) }
}

export const calculateAMRCoord = (sceneCoord = {}, datumMarkCoord = {}, datumMarkRotation = 0, n = 0) => {
  const sceneX = sceneCoord.x, sceneY = sceneCoord.y
  const x = datumMarkCoord.x / 1000, y = datumMarkCoord.y / 1000
  // 角度转换为弧度
  const angleRad = (datumMarkRotation * Math.PI) / 180

  // 计算旋转矩阵的逆（即转置）
  const cosTheta = Math.cos(angleRad), sinTheta = Math.sin(angleRad)

  // 平移矢量
  const dx = sceneX - x, dy = sceneY - y

  // 应用逆变换：旋转矩阵的逆乘以平移后的点
  const amrX = cosTheta * dx + sinTheta * dy, amrY = -sinTheta * dx + cosTheta * dy

  if (!n) return { x: formatNumber(amrX), y: formatNumber(amrY) }
  return { x: formatNumber(amrX * Math.pow(10, n), 0), y: formatNumber(amrY * Math.pow(10, n), 0) }
}

export const calculateQuaternionFromAxisAngle = ({ relativeX = 0, relativeY = 0, relativeZ = 0 }, angle = 0) => {
  // axis: 旋转轴，格式为 {x: number, y: number, z: number}, angle: 旋转角度（弧度制）
  angle = angle * Math.PI / 180
  // 计算旋转角的一半
  const halfAngle = angle / 2, sinHalfAngle = Math.sin(halfAngle), cosHalfAngle = Math.cos(halfAngle)

  // 归一化旋转轴
  const x = formatNumber(relativeX * 1000, 0), y = formatNumber(relativeY * 1000, 0),
    z = formatNumber(relativeZ * 1000, 0)
  const length = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2) + Math.pow(z, 2))
  const normalizedAxis = { x: x / length, y: y / length, z: z / length }

  // 计算四元数
  return {
    orientationW: formatNumber(cosHalfAngle, 6),
    orientationX: formatNumber(normalizedAxis.x * sinHalfAngle, 6),
    orientationY: formatNumber(normalizedAxis.y * sinHalfAngle, 6),
    orientationZ: formatNumber(normalizedAxis.z * sinHalfAngle, 6)
  }
}

const supportAMRImages = import.meta.glob('/src/views/MapCore/MapGlobal/assets/*.png')
export const formatAMRImage = (amrStatus = '', amrType = '') => {
  let imgSrc = 'FLT', suffix = ''
  if (['ERROR', 'EMERGENCY'].includes(amrStatus)) suffix = '_ALARM'
  else if (['RUNNING'].includes(amrStatus)) suffix = '_RUNNING'
  else if (['OFFLINE'].includes(amrStatus)) suffix = '_OFFLINE'
  else if (['CHARGING'].includes(amrStatus)) suffix = '_CHARGING'
  imgSrc = amrType ? `${amrType}_${imgSrc}${suffix}` : `${imgSrc}${suffix}`
  if (!supportAMRImages[`/src/views/MapCore/MapGlobal/assets/${imgSrc}.png`]) {
    imgSrc = imgSrc.replace(`${amrType}_`, '')
  }
  return new URL(`/src/views/MapCore/MapGlobal/assets/${imgSrc}.png`, import.meta.url).href
}